﻿using System.Dynamic;
using System.Globalization;
using System.Reflection;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Unicode;
using ApiLib.RCL.Utils.Converters;
using Console = System.Console;

namespace ApiLib.RCL.Utils;

/// <summary>
/// 通用基础类
/// </summary>
public static class CommonUtils
{
    /// <summary>
    /// JSON序列化，字符串会直接返回字符串
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static string Serialize(this object? obj)
    {
        return obj == null ? "" : obj as string ?? JsonSerializer.Serialize(obj, DefaultJsonSerializerOptions);
    }

    /// <summary>
    /// JSON反序列化
    /// </summary>
    /// <param name="content"></param>
    /// <returns></returns>
    public static T? Deserialize<T>(this string? content)
    {
        if (!string.IsNullOrEmpty(content))
        {
            try
            {
                return JsonSerializer.Deserialize<T>(content, DefaultJsonSerializerOptions);
            }
            catch (Exception e)
            {
                e.Message.LogError();
            }
        }

        return default;
    }

    public static readonly JsonSerializerOptions DefaultJsonSerializerOptions = new()
    {
        // PropertyNamingPolicy = JsonNamingPolicy.CamelCase;命名规则：CamelCase驼峰命名
        // IgnoreNullValues = true,已过时，推荐DefaultIgnoreCondition
        DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, //忽略所有默认值属性
        NumberHandling = JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString, //数字的序列化/反序列化方式
        AllowTrailingCommas = true, //允许尾部的逗号
        Encoder = JavaScriptEncoder.Create(UnicodeRanges.All),
        PropertyNameCaseInsensitive = true, //大小写不敏感
        Converters =
        {
            new ObjectAsPrimitiveConverter(),
            new SystemTextJsonConverter.DateTimeConverter(),
            new SystemTextJsonConverter.DateTimeNullableConverter()
        }
    };


    /// <summary>
    /// 对象转字典
    /// </summary>
    /// <param name="obj">对象</param>
    /// <returns></returns>
    public static Dictionary<string, object?> ToDictionary(this object obj)
    {
        var dictionary = new Dictionary<string, object?>();
        var properties = obj.GetType().GetProperties();
        foreach (var property in properties)
        {
            try
            {
                var value = property.GetValue(obj, null);
                dictionary.Add(property.Name, value);
            }
            catch (Exception e)
            {
                e.Message.LogError();
            }
        }

        return dictionary;
    }

    public static void LogError(this string message)
    {
        Console.WriteLine("Error: " + message);
    }

    #region 对象

    /// <summary>
    /// 类型转换
    /// </summary>
    /// <param name="data"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static object CommonConvert<T>(object? data)
    {
        if (data is T tVal)
        {
            return tVal;
        }

        if (typeof(T) == typeof(short))
        {
            return short.TryParse(data?.ToString(), out var num) ? num : 0;
        }

        if (typeof(T) == typeof(int))
        {
            return int.TryParse(data?.ToString(), out var num) ? num : 0;
        }

        if (typeof(T) == typeof(float))
        {
            return float.TryParse(data?.ToString(), out var num) ? num : 0;
        }

        if (typeof(T) == typeof(long))
        {
            return long.TryParse(data?.ToString(), out var num) ? num : 0;
        }

        if (typeof(T) == typeof(double))
        {
            return double.TryParse(data?.ToString(), out var num) ? num : 0;
        }

        if (typeof(T) == typeof(decimal))
        {
            return decimal.TryParse(data?.ToString(), out var num) ? num : 0;
        }

        if (typeof(T) == typeof(DateTime))
        {
            return DateTime.TryParse(data?.ToString(), out var num) ? num : 0;
        }

        return "";
    }

    /// <summary>
    /// 对象自动赋值
    /// </summary>
    /// <param name="model">源类</param>
    /// <param name="target">目标类</param>
    /// <param name="ignores">忽略的字段</param>
    /// <typeparam name="T">目标对象</typeparam>
    /// <returns></returns>
    public static T AutoMapping<T>(object? model, T? target, params string[] ignores) where T : new()
    {
        target ??= new T();
        if (model == null)
        {
            return target;
        }

        var properties = model.GetType().GetProperties();
        foreach (var property in properties)
        {
            if (ignores.Contains(property.Name)) continue;
            var targetProperty = target.GetType().GetProperty(property.Name);
            if (targetProperty == null) continue;
            try
            {
                var value = property.GetValue(model, null);
                if (value != null)
                {
                    targetProperty.SetValue(target, value, null);
                }
            }
            catch (Exception e)
            {
            }
        }

        return target;
    }

    /// <summary>
    /// 转换为动态对象
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static ExpandoObject ToExpandoObject(this object obj)
    {
        dynamic expando = new ExpandoObject();
        var expandoDict = (IDictionary<string, object>)expando;

        foreach (var property in obj.GetType().GetProperties())
        {
            expandoDict[property.Name] = property.GetValue(obj)??"";
        }

        return (expando as ExpandoObject)!;
    }
    
    /// <summary>
    /// 根据属性名设置值
    /// </summary>
    /// <param name="obj">对象</param>
    /// <param name="fieldName">属性名</param>
    /// <param name="value">值</param>
    /// <returns></returns>
    public static void SetFieldValue(this object obj, string fieldName, object? value)
    {
        var propertyInfo = obj.GetType().GetProperty(fieldName);
        propertyInfo.SetFieldValue(obj, value);
    }

    /// <summary>
    /// 根据属性名设置值
    /// </summary>
    /// <param name="propertyInfo">属性</param>
    /// <param name="obj">对象</param>
    /// <param name="value">值</param>
    /// <returns></returns>
    public static void SetFieldValue(this PropertyInfo? propertyInfo, object obj, object? value)
    {
        if (propertyInfo == null) return;
        if (value == null) return;
        try
        {
            object? value2 = null;
            if (propertyInfo.PropertyType != value.GetType())
            {
                if (propertyInfo.PropertyType == typeof(string))
                {
                    value2 = value as string ?? value.ToString();
                }
                else if ((propertyInfo.PropertyType == typeof(DateTime) ||
                          propertyInfo.PropertyType == typeof(DateTime?))
                         && value is not DateTime)
                {
                    value2 = (value?.ToString() ?? "").ToDateTime();
                }
                else if ((propertyInfo.PropertyType == typeof(bool) || propertyInfo.PropertyType == typeof(bool?))
                         && value is not bool)
                {
                    var strVal = value.ToString() ?? "";
                    if (strVal is "是" or "1")
                    {
                        value2 = true;
                    }
                    else
                    {
                        value2 = bool.TryParse(strVal, out var boolVal) && boolVal;
                    }
                }
                else if ((propertyInfo.PropertyType == typeof(int) || propertyInfo.PropertyType == typeof(int?))
                         && value is not int
                         && int.TryParse(value.ToString() ?? "", out var intVal))
                {
                    value2 = intVal;
                }
                else if ((propertyInfo.PropertyType == typeof(double) || propertyInfo.PropertyType == typeof(double?))
                         && value is not double
                         && double.TryParse(value.ToString() ?? "", out var doubleVal))
                {
                    value2 = doubleVal;
                }
                else if ((propertyInfo.PropertyType == typeof(float) || propertyInfo.PropertyType == typeof(float?))
                         && value is not float
                         && float.TryParse(value.ToString() ?? "", out var floatVal))
                {
                    value2 = floatVal;
                }
                else if ((propertyInfo.PropertyType == typeof(decimal) || propertyInfo.PropertyType == typeof(decimal?))
                         && value is not decimal
                         && decimal.TryParse(value.ToString() ?? "", out var decimalVal))
                {
                    value2 = decimalVal;
                }
            }

            value2 ??= value;
            propertyInfo.SetValue(obj, value2, null);
        }
        catch (Exception e)
        {
            e.Message.LogError();
        }
    }
    
    /// <summary>
    /// 根据属性名获取值
    /// </summary>
    /// <param name="obj">对象</param>
    /// <param name="fieldName">属性名</param>
    /// <returns></returns>
    public static object? GetFieldValue(this object obj, string fieldName)
    {
        var propertyInfo = obj.GetType().GetProperty(fieldName);
        if (propertyInfo != null)
        {
            try
            {
                return propertyInfo.GetValue(obj, null);
            }
            catch (Exception e)
            {
                e.Message.LogError();
            }
        }

        return null;
    }
    
    
    
    #endregion

    #region 时间

    
    /// <summary>
    /// 字符串转时间
    /// </summary>
    /// <param name="dateTimeStr"></param>
    /// <param name="format">yyyy-MM-dd HH:mm:ss</param>
    /// <returns></returns>
    public static DateTime? ToDateTime(this string dateTimeStr, string? format = null)
    {
        if (string.IsNullOrEmpty(format))
        {
            format = "yyyy-MM-dd HH:mm:ss";
        }

        try
        {
            return DateTime.ParseExact(dateTimeStr, format, CultureInfo.CurrentCulture);
        }
        catch (Exception e)
        {
            return default;
        }
    }
    
    /// <summary>
    /// 当天开始时间
    /// </summary>
    /// <param name="now"></param>
    /// <returns></returns>
    public static DateTime DayStart(this DateTime now)
    {
        return new DateTime(now.Year, now.Month, now.Day, 0, 0, 0);
    }

    /// <summary>
    /// 当天结束时间
    /// </summary>
    /// <param name="now"></param>
    /// <returns></returns>
    public static DateTime DayEnd(this DateTime now)
    {
        return new DateTime(now.Year, now.Month, now.Day, 23, 59, 59);
    }

    /// <summary>
    /// 当月开始时间
    /// </summary>
    /// <param name="now"></param>
    /// <returns></returns>
    public static DateTime MonthStart(this DateTime now)
    {
        return new DateTime(now.Year, now.Month, 1, 0, 0, 0);
    }

    /// <summary>
    /// 当月结束时间
    /// </summary>
    /// <param name="now"></param>
    /// <returns></returns>
    public static DateTime MonthEnd(this DateTime now)
    {
        var time = now.AddDays(1 - now.Day).AddMonths(1).AddDays(-1);
        return new DateTime(time.Year, time.Month, time.Day, 23, 59, 59);
    }

    /// <summary>
    /// 当年开始时间
    /// </summary>
    /// <param name="now"></param>
    /// <returns></returns>
    public static DateTime YearStart(this DateTime now)
    {
        return new DateTime(now.Year, 1, 1, 0, 0, 0);
    }

    /// <summary>
    /// 当年结束时间
    /// </summary>
    /// <param name="now"></param>
    /// <returns></returns>
    public static DateTime YearEnd(this DateTime now)
    {
        var time = now.AddDays(1 - now.DayOfYear).AddYears(1).AddDays(-1);
        return new DateTime(time.Year, time.Month, time.Day, 23, 59, 59);
    }
    #endregion
}